package com.gitee.kamismile.stoneComEx.common.exception.servlet;

import com.gitee.kamismile.stone.commmon.base.ResultVO;
import com.gitee.kamismile.stone.commmon.exception.BusinessException;
import com.gitee.kamismile.stone.commmon.util.JsonUtil;
import com.gitee.kamismile.stone.commmon.util.ValueUtils;
import com.gitee.kamismile.stoneComEx.util.IpUtil;
import jakarta.servlet.http.HttpServletRequest;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.TypeMismatchException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.context.support.ReloadableResourceBundleMessageSource;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.ServletRequestBindingException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.multipart.MaxUploadSizeExceededException;
import org.springframework.web.multipart.MultipartException;
import org.springframework.web.multipart.support.MultipartResolutionDelegate;
import org.springframework.web.servlet.NoHandlerFoundException;
import org.springframework.web.util.ContentCachingRequestWrapper;
import org.springframework.web.util.WebUtils;

import java.nio.charset.StandardCharsets;
import java.text.MessageFormat;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Created by lidong on 15-9-8.
 */
@ControllerAdvice
public class SimpleException {
    protected final Logger logger =LoggerFactory.getLogger(getClass());

    @Autowired
    private ReloadableResourceBundleMessageSource messageSource;


    @ExceptionHandler(Throwable.class)
    public ResponseEntity<Map> handleException(Throwable ex,
                                               HttpServletRequest request) {
        ResultVO errorMsg = new ResultVO();

        Locale locale = LocaleContextHolder.getLocale();
        int code = -1;
        String defMessage = messageSource.getMessage(String.valueOf(code), null, locale);

        if (ex instanceof BusinessException) {
            code = ((BusinessException) ex).getCode();
            defMessage = messageSource.getMessage(String.valueOf(code), ((BusinessException) ex).getArgs(), locale);
            if(defMessage.equals(String.valueOf(code))){
                defMessage = ValueUtils.isStringNull(((BusinessException) ex).getMessage());
            }
            errorMsg.setData(((BusinessException) ex).getData());
        } else if (ex instanceof MissingServletRequestParameterException) {
            code = 400;
            defMessage = ex.getMessage();
        } else if (ex instanceof NoHandlerFoundException) {
            defMessage = "page not found";
            code = 404;
        } else if (ex instanceof DuplicateKeyException) {
            if (((DuplicateKeyException) ex).toString().indexOf("ORA-00001") != -1) {
                defMessage = messageSource.getMessage("10001", null, locale);
            }
        } else if (ex instanceof TypeMismatchException) {
            code = 400;
            defMessage = messageSource.getMessage("10002", null, locale);
        } else if (ex instanceof ServletRequestBindingException) {
            code = 400;
            defMessage = messageSource.getMessage("10003", null, locale);
        } else if (ex instanceof HttpMessageNotReadableException) {
            code = 400;
            defMessage = messageSource.getMessage("10003", null, locale);
        } else if (ex instanceof IllegalArgumentException) {
            code = 400;
            defMessage = ex.getMessage();
        } else if (ex instanceof org.springframework.web.bind.MethodArgumentNotValidException) {
            code = 400;
            defMessage = ((MethodArgumentNotValidException) ex).getBindingResult()
                    .getFieldError().getDefaultMessage();
        } else if (ex instanceof MultipartException
                || ex instanceof MaxUploadSizeExceededException) {
            String _msg = ex.getMessage();
            Pattern pat = Pattern.compile("maximum \\((\\d+)\\)");
            Matcher mat = pat.matcher(_msg);
            if (mat.find()) {
                defMessage = "单个文件限制在" + ValueUtils.convertToFileSize(Long.parseLong(mat.group(1))) + "以下.";
            } else {
                defMessage = _msg;
            }
        }

        Enumeration<String> names = request.getHeaderNames();
        Map<String, String> nameMap = new HashMap<>();
        while (names.hasMoreElements()) {
            String name = names.nextElement();
            String value = request.getHeader(name);
            nameMap.put(name, value);
        }

        logger.error(MessageFormat.format("调用接口:{0} {1} {2} 调用参数:{3}  IP:{4} 异常信息:{5}{6}",
                request.getMethod(), nameMap,
                ValueUtils.isStringNull(request.getAttribute(ServletErrorEnum.URL.getTypeName()), request.getRequestURI()),
                JsonUtil.toJson(getRequestMap(request)), IpUtil.getIp(request),defMessage, ExceptionUtils.getStackTrace(ex)));

//        LoggerInfoVO loggerInfoVO = new LoggerInfoVO();
//        loggerInfoVO.setMethodName(request.getMethod());
//        loggerInfoVO.setHeaders(JsonUtil.toJson(nameMap));
//        loggerInfoVO.setUrl(ValueUtils.isStringNull(request.getAttribute(ServletErrorEnum.URL.getTypeName()), request.getRequestURI()));
//        loggerInfoVO.setIp(IpUtil.getIp(request));
//        loggerInfoVO.setRequestBody(JsonUtil.toJson(getRequestMap(request)));
//        loggerInfoVO.setMessage(message);
//        loggerInfoVO.setEx(ExceptionUtils.getStackTrace(ex));
//
//        logger.error("{}",JsonUtil.toJson(loggerInfoVO));

        errorMsg.setCode(ValueUtils.isStringNull(code));
        errorMsg.setMessage(defMessage);

        Map responseMap = new HashMap();
        responseMap.put("code", errorMsg.getCode());
        responseMap.put("data", errorMsg.getData());
        responseMap.put("message", errorMsg.getMessage());
        responseMap.put("errors", Arrays.asList(errorMsg));
        HttpStatus httpStatus = HttpStatus.resolve(code);
        httpStatus= Objects.isNull(httpStatus)?HttpStatus.OK:httpStatus;
        return new ResponseEntity<Map>(responseMap, httpStatus);
    }


    private Map<String, String> getRequestMap(HttpServletRequest request) {
        Object requestObj = request;
        Map<String, String[]> parameterMap = request.getParameterMap();
        Map<String, String> map = new HashMap<String, String>();
        Iterator<String> it = parameterMap.keySet().iterator();
        while (it.hasNext()) {
            String objs = (String) it.next();
            String[] obj = (String[]) parameterMap.get(objs);
            map.put(objs, StringUtils.join(obj, ","));
        }
        boolean isMultipart = MultipartResolutionDelegate.isMultipartRequest(request);
        if (!isMultipart) {
            String requestBody = "";
            ContentCachingRequestWrapper wrapper = WebUtils.getNativeRequest(request, ContentCachingRequestWrapper.class);
            if (Objects.nonNull(wrapper)) {
                requestBody = new String(wrapper.getContentAsByteArray(), StandardCharsets.UTF_8);
            }
            map.put("requestBody", requestBody);
        }
        return map;
    }
}
